package com.tajlip;

import com.google.appengine.api.datastore.Blob;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.SortDirection;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Handles file uploads. This uses a little bit of helper code that Jayson wrote
 * to parse multipart HTML POST methods and extract both parameters and binary
 * data. Note, we can't upload anything > 10MB due to Google's HTTP request
 * size limitations. However, our images should safely be below this size limit.
 */
public class UploadFilter implements Filter {

    private FilterConfig filterConfig = null;

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ServletInputStream sis = req.getInputStream();
        byte[] buf = new byte[1000];
        for (int bytesRead = 0; bytesRead != -1; bytesRead = sis.read(buf)) {
            baos.write(buf, 0, bytesRead);
        }

        // try to make a new comic
        Comic comic = new Comic();
        comic.timestamp = System.currentTimeMillis();

        // parse the uploaded files
        byte[] body = baos.toByteArray();
        Map<String /* name */, FileUpload> uploads = FileUploadUtil.readUpload(body);
//        out.println("*** Parsed " + uploads.size() + " File Uploads ***");
        for (FileUpload upload : uploads.values()) {
//            System.out.println("*** Parsed Upload ***");
//            System.out.println("  Name: " + upload.name);
//            System.out.println("  File Name: " + upload.filename);
//            System.out.println("  Content Length: " + upload.data.length);

            // set the named values
            if (upload.name.equals("tags")) {
                comic.tags = new String(upload.data);
            }
            if (upload.name.equals("title")) {
                comic.title = new String(upload.data);
            }
            if (upload.name.equals("description")) {
                comic.description = new String(upload.data);
            }

            // save the image
            if (upload.name.equals("image")) {
                comic.image = new Blob(upload.data);
            }
            // save the image thumbnail
            if (upload.name.equals("image-thumb")) {
                comic.imageSmall = new Blob(upload.data);
            }
        }

//        // debug
//        System.out.println("Title:" + comic.title);
//        System.out.println("Description:" + comic.description);
//        System.out.println("Tags:" + comic.tags);
//        System.out.println("Image Size: " + comic.image.getBytes().length);
//        System.out.println("Image Thumb Size: " + comic.imageSmall.getBytes().length);

        // show the upload page if any data is missing -- e.g. user is first seeing the upload page
        if (comic.title == null ||
                comic.description == null ||
                comic.tags == null) {
            req.getRequestDispatcher("upload.jsp").forward(request, response);
            // don't execute the rest of this filter
            return;
        }

        // access Google's database
        DatastoreService dataService = DatastoreServiceFactory.getDatastoreService();

        // find the next unique comic ID
        long nextUniqueID = 1;
        // query all the comies from BigTable
        Query query = new Query(Comic.KIND);
        PreparedQuery preparedQuery = dataService.prepare(query);
        for (Entity entity : preparedQuery.asIterable()) {
            long existingID = (Long) entity.getProperty("id");
            nextUniqueID = Math.max(nextUniqueID, existingID + 1);
        }

        // try to create the comic
        Entity entity = new Entity(Comic.KIND);
        entity.setProperty("id", nextUniqueID);
        entity.setUnindexedProperty("title", comic.title);
        entity.setUnindexedProperty("description", comic.description);
        entity.setUnindexedProperty("tags", comic.tags);
        entity.setProperty("timestamp", comic.timestamp);
        entity.setUnindexedProperty("image", comic.image);
        entity.setUnindexedProperty("image-small", comic.imageSmall);

        // file name is the key -- we don't do anything with this
        Key key = dataService.put(entity);

        // HTTP redirect to the list of comics
        res.sendRedirect("edit.html");
    }

    public void destroy() {
    }

    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }
}